#include "Homework4.h"
#include <string.h>

void Homework4::test1()
{
    cout << "start Test1" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SegmentManager& segMan = DB::getDB().getSegmentManager();
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    const char* data = "Hallo Welt";
    const Record r_soll(10 , data);
    const char* data_soll = r_soll.getData();

    for (unsigned i = 0; i < r_soll.getLen(); i++)
    {
        assert(data[i] == data_soll[i]);
    }

    TID t = spSeg.insert(r_soll);
    Record r_ist = spSeg.lookup(t);

    assert(r_soll.getLen() == r_ist.getLen());
    const char* data_ist = r_ist.getData();
    for (unsigned i = 0; i < r_soll.getLen(); i++)
    {
        assert(data_soll[i] == data_ist[i]);
    }

    assert(spSeg.deleteRecord(t));

    assert(!spSeg.lookup(t).getData());
    cout << "end Test1" << endl;
}

/**
Try to overflow a page
*/
void Homework4::test2()
{
    cout << "start Test2" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SegmentManager& segMan = DB::getDB().getSegmentManager();
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    const unsigned blaCount = 20000;
    cout << "COUNT: " << blaCount << endl;
    TID ts[blaCount];

    for (unsigned i = 0; i < blaCount; i++)
    {
        const char* data = "Nein man ich will noch nicht gehn, ich will noch n bissl DB proggen^^";
        const Record r_soll(69 , data);
        ts[i] = spSeg.insert(r_soll);
    }

    for (unsigned i = 0; i < blaCount; i++)
    {
        const char* data = "Nein man ich will noch nicht gehn, ich will noch n bissl DB proggen^^";
        const Record r_soll(69 , data);
        Record r_ist = spSeg.lookup(ts[i]);
        assert(r_soll.getLen() == r_ist.getLen());
        const char* data_ist = r_ist.getData();
        const char* data_soll = r_soll.getData();
        for (unsigned i = 0; i < r_soll.getLen(); i++)
        {
            assert(data_soll[i] == data_ist[i]);
        }
    }

    for (unsigned i = 0; i < blaCount; i++)
    {
        spSeg.deleteRecord(ts[i]);
        assert(!spSeg.lookup(ts[i]).getData());
    }
    cout << "end Test2" << endl;
}

/**
Test update
*/
void Homework4::test3()
{
    cout << "start Test3" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SegmentManager& segMan = DB::getDB().getSegmentManager();
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    const char* data = "UpdateTest";
    const Record r_alt(10, data);
    TID t = spSeg.insert(r_alt);

    const Record r_neu(7, "changed");
    assert(spSeg.update(t, r_neu));

    Record r_ist = spSeg.lookup(t);

    assert(r_neu.getLen() == r_ist.getLen());
    const char* data_ist = r_ist.getData();
    const char* data_neu = r_neu.getData();
    for (unsigned i = 0; i < r_neu.getLen(); i++)
    {
        assert(data_neu[i] == data_ist[i]);
    }
    cout << "end Test3" << endl;
}

/**
Test update
*/
void Homework4::test4()
{
    cout << "start Test4" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SegmentManager& segMan = DB::getDB().getSegmentManager();
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    const char* data = "UpdateTest";
    const Record r_alt(10, data);
    TID t = spSeg.insert(r_alt);

    const Record r_neu(7, "changed");
    assert(spSeg.update(t, r_neu, false));

    Record r_ist = spSeg.lookup(t);

    assert(r_neu.getLen() == r_ist.getLen());
    const char* data_ist = r_ist.getData();
    const char* data_neu = r_neu.getData();
    for (unsigned i = 0; i < r_neu.getLen(); i++)
    {
        assert(data_neu[i] == data_ist[i]);
    }
    cout << "end Test4" << endl;
}

/**
Test update
*/
void Homework4::test5()
{
    cout << "start Test5" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SegmentManager& segMan = DB::getDB().getSegmentManager();
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    const char* data = "Nein man ich will noch nicht gehn, ich will noch n bissl DB proggen^^";
    const Record r_alt(69, data);
    TID t = spSeg.insert(r_alt);
    const unsigned blaCount = 1000;

    for (unsigned i = 0; i < blaCount; i++)
    {
        char bla[10];
        const Record dontCare(10, bla);//"0123456789");
        spSeg.insert(dontCare);
    }

    //Page should be full now
    Record r_ist = spSeg.lookup(t);
    assert(r_alt.getLen() == r_ist.getLen());
    const char* data_ist = r_ist.getData();
    for (unsigned i = 0; i < r_ist.getLen(); i++)
    {
        assert(data[i] == data_ist[i]);
    }

    const char* dataUpdate = "neuerDatenSchmuh";
    const Record r_up = Record(16, dataUpdate);
    assert(spSeg.update(t, r_up));

    for (unsigned i = 0; i < blaCount; i++)
    {
        const Record dontCare(11, "0123456789");
        spSeg.insert(dontCare);
    }

    Record r_ist_2 = spSeg.lookup(t);
    assert(r_up.getLen() == r_ist_2.getLen());
    const char* data_ist_2 = r_ist_2.getData();
    for (unsigned i = 0; i < r_ist_2.getLen(); i++)
    {
        assert(dataUpdate[i] == data_ist_2[i]);
    }

    cout << "end Test5" << endl;
}

/**
Test update
*/
void Homework4::test6()
{
    cout << "start Test6" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SegmentManager& segMan = DB::getDB().getSegmentManager();
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    const char* data = "Nein man ich will noch nicht gehn, ich will noch n bissl DB proggen";
    const Record r_alt(69, data);
    TID t = spSeg.insert(r_alt);
    const unsigned blaCount = 10;

    for (unsigned i = 0; i < blaCount; i++)
    {
        char bla[10];
        const Record dontCare(10, bla);
        spSeg.insert(dontCare);
    }

    cout << "vor Update" << endl;
    cout << "pageId: " << t.pageId << endl;
    cout << "slotId: " << t.slotId << endl;

    //Page should be full now
    Record r_ist = spSeg.lookup(t);
    assert(r_alt.getLen() == r_ist.getLen());
    const char* data_ist = r_ist.getData();
    for (unsigned i = 0; i < r_ist.getLen(); i++)
    {
        assert(data[i] == data_ist[i]);
    }

    const char* dataUpdate = "neuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuhneuerDatenSchmuh";
    const Record r_up = Record(273, dataUpdate);

    assert(spSeg.update(t, r_up));
    /*
        cout << "nach Update" << endl;
        cout << "pageId: " << t.pageId << endl;
        cout << "slotId: " << t.slotId << endl;
    */
    for (unsigned i = 0; i < blaCount; i++)
    {
        char bla[10];
        const Record dontCare(10, bla);
        spSeg.insert(dontCare);
    }

    Record r_ist_2 = spSeg.lookup(t);
    /*
        cout << r_up.getLen() << endl;
        for(unsigned i = 0; i < r_up.getLen(); i++)
        {
            cout << r_up.getData()[i];
        }
        cout << endl << r_ist_2.getLen() << endl;
        for(unsigned i = 0; i < r_ist_2.getLen(); i++)
        {
            cout << r_ist_2.getData()[i];
        }

        cout << endl;
    */
    assert(r_up.getLen() == r_ist_2.getLen());
    const char* data_ist_2 = r_ist_2.getData();
    for (unsigned i = 0; i < r_ist_2.getLen(); i++)
    {
        assert(dataUpdate[i] == data_ist_2[i]);
    }

    cout << "end Test6" << endl;
}

void Homework4::stressTest()
{
    cout << "start stressTest" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SegmentManager& segMan = DB::getDB().getSegmentManager();
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    unsigned insertCount = 0;
    unsigned deleteCount = 0;
    unsigned lookUpCount = 0;
    unsigned updateCount = 0;
    vector<TID> ts;

    const unsigned blaCount = 10000;

    for (unsigned i = 0; i < blaCount; i++)
    {
        unsigned x = rand() % 6;

        if (x <= 1)
        {
            if (ts.size() == 0)
            {
                i--;
                break;
            }
            updateCount++;
            unsigned size_ = rand() % 100;
            char newData[size_];
            const Record newRec_(size_, newData);
            assert(spSeg.update(ts[rand() % ts.size()], newRec_));
        }
        else if (x <= 2)
        {
            if (ts.size() == 0)
            {
                i--;
                break;
            }
            deleteCount++;
            unsigned index_ = rand() % ts.size();
            assert(spSeg.deleteRecord(ts[index_]));
            ts.erase(ts.begin() + index_);
        }
        else if (x <= 4)
        {
            if (ts.size() == 0)
            {
                i--;
                break;
            }
            lookUpCount++;
            assert(spSeg.lookup(ts[rand() % ts.size()]).getData() != NULL);
        }
        else
        {
            insertCount++;
            unsigned size = rand() % 100;
            char newData[size];
            const Record newRec(size, newData);
            ts.push_back(spSeg.insert(newRec));
        }
    }

    cout << "insertCount: " << insertCount;
    cout << "deleteCount: " << deleteCount;
    cout << "lookUpCount: " << lookUpCount;
    cout << "updateCount: " << updateCount;

    cout << "end stressTest" << endl;
}
/*
void Homework4::concTest()
{
    cout << "start concTest" << endl;
    Hausaufgabe3_Test::createFile(DB_FILE.c_str(), DB_FILE_SIZE);
    SingleBufferManager buffMan(DB_FILE.c_str(), 10);
    SegmentInventory segInv(buffMan, DB_FILE_SIZE);
    SegmentManager segMan(buffMan, segInv);
    Segment& seg = segMan.createSegment();
    SPSegment spSeg(seg);

    const unsigned THREAD_COUNT = 20;
//    SEM_CREATE(sem);
//    nextId = 0;

    pthread_t thread[THREAD_COUNT];
    for(unsigned i = 0; i < THREAD_COUNT; i++)
    {
        pthread_create (&thread[i], NULL, concTest, &spSeg);
    }

    for(unsigned i = 0; i < THREAD_COUNT; i++)
    {
        pthread_join(thread[i], NULL);
    }

//    SEM_DESTROY(sem);
}

void *Homework4::concTest(void* arg)
{
 //   SEM_WRITELOCK(sem);
 //   unsigned threadId = nextId++;
 //   SEM_UNLOCK(sem);

    const unsigned blaCount = 1000;
    const unsigned mySize = 20;

    for(unsigned i = 0; i < blaCount; i++)
    {
        unsigned x = rand() % 6;

        if(x <= 1)
        {
            if(ts.size() == 0)
            {
                i--;
                break;
            }
            char newData[mySize];
            const Record newRec_(mySize, newData);
            assert(spSeg.update(ts[rand() % ts.size()], newRec_));
        }
        else if(x <= 2)
        {
            if(ts.size() == 0)
            {
                i--;
                break;
            }
            unsigned index_ = rand() % ts.size();
            assert(spSeg.deleteRecord(ts[index_]));
            ts.erase(ts.begin() + index_);
        }
        else if(x <= 4)
        {
            if(ts.size() == 0)
            {
                i--;
                break;
            }
            assert(spSeg.lookup(ts[rand() % ts.size()]).getData() != NULL);
        }
        else
        {
            char newData[mySize];
            const Record newRec(mySize, newData);
            ts.push_back(spSeg.insert(newRec));
        }
    }
}
*/
